【翻译】On the ES6 module syntax

这篇文章将会探索ES6的模块以及它与Node的模块(commonJS)的不同。模块系统本质上就是一种从一个文件中引用另一个文件的方法。基本上任何东西都可以被赋值给一个变量。模块系统选择一系列标准的愈发来使得它更容易书写。

先前,我只使用过Node的模块系统。随着我最近探索ES6,我发现Node和ES6的模块系统之间有一些不一样的。本质上,它们做的是同样的事,但是它们的语法有些轻微的不同。

让我们以一个可以给你推荐一杯鸡尾酒的函数作为例子。为了保持简单,这个函数总是会给你推荐一杯“Sazerac”鸡尾酒(这不是一个坏事情)。

1
2
3
4
5
6
function getCocktail() {
return "Sazerac";
}

在Node中,如果你想在一个文件中定义这个函数,然后在另一个文件中使用它,你将会使用module.exports

cocktail.js:

1
2
3
4
5
6
7
8
function getCocktail() {
return "Sazerac";
}
module.exports = getCocktail;

要想在另一个文件中使用它,你必须使用require

app.js:

1
2
3
4
5
6
7
8
9
10
11
12
var getCocktail = require('./cocktail');
// you don't need the file extension here
// ./ means that you are including a file from the same directory
// the variable getCocktail is now set to the function getCocktail() from cocktail.js
// this means we can call it:
console.log(getCocktail()) // logs "Sazerac";

这就是Node处理模块系统的方法,ES6的模块方法则有些不一样。

cocktail.js:

1
2
3
4
5
6
7
8
9
10
function getCocktail() {
retrun "Sazerac";
}
export default getCocktail;

app.js:

1
2
3
4
5
6
import 'getCocktail' from './cocktail' // you don't net the file extension here either;
console.log(getCocktail()); // "Sazerac";

让我们来总结下Node和ES6的不同, 如何引入:

  • require('module') // Node

  • import thing from 'module' // ES6

以及如何导出:

  • module.exports = thing // Node

  • export default thing // ES6

导出多种东西

模块系统的一个共同用例是一个模块可以导出好几个关联的东西。我们来扩展鸡尾酒例子,让它能够给你推荐威士忌、杜松子酒和处女鸡尾酒。

在Node中,你可以导出一个包含多样东西的对象:

cocktail.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function getWhiskyCocktail() {
return "Sazerac";
}
function getGinCocktail() {
return "Martini"; // stirred, obviously
}
function getVirginCocktail() {
return "Virgin Mary";
}
module.exports = {getGinCocktail, getVirginCocktail, getWhiskyCocktail};

为了调用它,你得通过一个对象才能做到:

app.js:

1
2
3
4
5
6
7
8
var cockttails = require('./cocktail');
console.log(cocktails.getGinCocktail()); // Martini
console.log(cocktails.getVirginCocktail()); // Virgin Mary

我个人认为, ES6在这方面做个稍微好点。

cocktail.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function getWhiskyCocktail() {
return "Sazerac";
}
function getGinCocktail() {
return "Martini"; // stirred, obviously
}
function getVirginCocktail() {
return "Virgin Mary";
}
export {getGinCocktail, getVirginCocktail, getWhiskyCocktail};

app.js:

1
2
3
4
5
6
7
8
import {getGinCocktail, getVirginCocktail} from './cocktail';
console.log(cocktails.getGinCocktail()); // Martini
console.log(cocktails.getVirginCocktail()); // Virgin Mary

正如你所见,首先,你可以直接调用函数而不必通过一个对象。另外,ES6模块系统能够让你只引入你需要的函数(所以如果你不是一个威士忌粉丝, 这将非常适合你)。如果你正在性能优化,这也许会节约一些内存使用,但是我不确定。(谁能够证实或否定它?)

细心的观众可能注意到第一个ES6例子使用 export default thing,而第二个例子使用 export {thing, otherThing}。如果你正在写一个模块并且你推测一个方法将会比其他方法使用得更频繁,你可以将它设置成默认。你可以同时使用默认或者非默认(命名)导出。

cocktail.js:

1
2
3
4
export default getWhiskyCocktail;
export {getGinCocktail, getVirginCocktail};

所以如果你只是对默认的威士忌酒感兴趣,你可以这么写:

app.js

1
2
3
4
import getWhiskyCocktail from './cocktail';
console.log(getWhiskyCocktail()); // Sazerac

或者你既想要默认的威士忌酒也想要处女鸡尾酒:

app.js

1
2
3
4
5
6
import getWhiskyCocktail, {getVirginCocktail} from './cocktail';
console.log(getWhiskyCocktail()); // Sazerac
console.log(getVirginCocktail()); // Virgin Mary

必需注意到ES6表示导入命名的导出方法是它被花括号包围着,即使你只是导入它们中的一个,这非常重要。如果你没有使用花括号,你将会试图是访问默认的导出方法。我一开始就在这上面踩了坑。

1
2
export {getGinCocktail, getVirginCocktail, getWhiskyCocktail};
1
2
3
4
import getWhiskyCocktail from './cocktail';
console.log(getWhiskyCocktail()); // error!

如果你愿意的话,你也可以在导入方法的时候使用as newName来重命名它们。

1
2
3
4
import {getWhiskyCocktail as getCocktail} from './cocktail';
console.log(getCocktail()); // Sazerac

关于ES6模块系统还有更多的东西,我今天只是覆盖了一点点。如果你想要链接更多,我给你推荐一下的资源:

我讲完了,非常感谢你的阅读。

原文链接

作者: Alex Jegtnes